package com.lanyou.cook.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.collections4.map.MultiKeyMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.ui.velocity.VelocityEngineFactoryBean;
import org.springframework.ui.velocity.VelocityEngineUtils;
import com.google.gson.JsonObject;
import com.lanyou.cook.entity.domain.InterfaceExceptionNotify;
import com.lanyou.cook.entity.domain.userManagement.User;
import com.lanyou.cook.paramsetting.Keys;
import com.lanyou.cook.paramsetting.ParamSettingService;
import com.lanyou.cook.repository.InterfaceExceptionNotifyRepository;
import com.lanyou.cook.repository.userManagement.UserRepository;
import com.lanyou.cook.service.vo.ErrorReportParam;
import com.lanyou.cook.util.MailUtil;
import com.lanyou.cook.util.gson.GsonUtil;
import com.lanyou.esb.entity.ClusterNode;

@Service
public class SendEmailService {
	
	@Autowired
	private ParamSettingService paramSettingService;
	
	private ExecutorService executorService;
	
	@PersistenceContext
	private EntityManager entityManager;
	
	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private InterfaceExceptionNotifyRepository interfaceExceptionNotifyRepository;
	
	private ConcurrentMap<User, MultiKeyMap<String, Long>> map = new ConcurrentHashMap<>();
	
	
	private static final FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
	
	@PostConstruct
	private void init(){
		executorService = Executors.newCachedThreadPool();
	}
	
	public void addErrorNotification(Collection<User> users, ErrorReportParam vo, boolean immediately){
		if (immediately) {
			//出错立即发送错误通知
			vo.setRunTime(fastDateFormat.format(new Date()));
			vo.setErrorCount(1L);
			Collection<ErrorReportParam> eps = Arrays.asList(vo);
			users.stream().forEach(u -> executorService.execute(() -> {
				try{
					sendMail(u,eps,"FailureWarningInfoReportTemplate");
				} catch (Exception e){
				}
			}));
		} else {
			/*users.stream().forEach(u -> {
				map.putIfAbsent(u, new MultiKeyMap<>());
				MultiKeyMap<String, Long> map3 = map.get(u);
				synchronized (map3) {
					Long errorCount = map3.get(vo.getFieldName(), vo.getFieldSystemName(), vo.getInterfaceName());
					if (errorCount == null) {
						errorCount = 0L;
					}
					errorCount += 1;
					map3.put(vo.getFieldName(), vo.getFieldSystemName(), vo.getInterfaceName(), errorCount);
				}
				
			});*/
			InterfaceExceptionNotify interfaceExceptionNotify = new InterfaceExceptionNotify();
			List<String> userCodes = new ArrayList<String>();
			for (User user : users) {
				userCodes.add(user.getUserCode());
			}
			String sendToUsers = StringUtils.join(userCodes, ";");
			interfaceExceptionNotify.setSendToUsers(sendToUsers);
			interfaceExceptionNotify.setFieldName(vo.getFieldName());
			interfaceExceptionNotify.setFieldSystemName(vo.getFieldSystemName());
			interfaceExceptionNotify.setInterfaceName(vo.getInterfaceName());
			interfaceExceptionNotify.setRunBeginTime(fastDateFormat.format(new Date()));
			interfaceExceptionNotifyRepository.save(interfaceExceptionNotify);
		}
	}
	
	//统一在定时在第二天早上八点钟发送
	/*@Scheduled(cron = "0 0 11 * * ?")
	public void timeCheckSend() throws IOException{
		同步前
		String dateStr = getExceptionTimeSlot();
		
		//String dateStr = getExceptionTimeSlot();
		setMailMap();
		for(Map.Entry<User, MultiKeyMap<String, Long>> entry : map.entrySet()){
			
			User user = entry.getKey();
			List<ErrorReportParam> eps= new ArrayList<ErrorReportParam>();
			entry.getValue().entrySet().stream().forEach(entry2 -> {
				
				Object[] keys = entry2.getKey().getKeys();
				Long errorCount = entry2.getValue();
				ErrorReportParam ep = new ErrorReportParam();
				ep.setFieldName(keys[0].toString());
				ep.setFieldSystemName(keys[1].toString());
				ep.setInterfaceName(keys[2].toString());
				ep.setErrorCount(errorCount);
				同步前
				//Date now = new Date();
				//Date oneDayAgo = DateUtils.addDays(now, -1);
				//String dateStr = String.format("%s - %s", fastDateFormat.format(oneDayAgo), fastDateFormat.format(now));
				
				Date now = new Date();
				Date oneDayAgo = DateUtils.addDays(now, -1);
				String dateStr = String.format("%s - %s", fastDateFormat.format(oneDayAgo), fastDateFormat.format(now));
				ep.setRunTime(dateStr);
				eps.add(ep);
			});
			sendMail(user,eps,"FailureWarningInfoReportTemplate");
			
		}
		map.clear();
		interfaceExceptionNotifyRepository.deleteAll();
	}*/
	
	
	private void sendMail(User user,Collection<ErrorReportParam> eps,String templateName) throws IOException{
		
		/*JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl();
		
		JsonObject smtpService = paramSettingService.getAsJson(Keys.SMTP).getAsJsonObject();
		javaMailSenderImpl.setHost(GsonUtil.getString(smtpService, "smtpAddress", ""));
		javaMailSenderImpl.setPort(Integer.parseInt(GsonUtil.getString(smtpService, "port", "")));
		javaMailSenderImpl.setUsername(GsonUtil.getString(smtpService, "userCode", ""));
		javaMailSenderImpl.setPassword(GsonUtil.getString(smtpService, "password", ""));
		
		
		Properties javaMailProperties = new Properties();
		javaMailProperties.put(" mail.smtp.auth ", " true "); // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确
		javaMailProperties.put(" mail.smtp.timeout ", " 25000 ");
		javaMailSenderImpl.setJavaMailProperties(javaMailProperties);
		
		VelocityEngineFactoryBean velocityEngineFactoryBean = new VelocityEngineFactoryBean();
		velocityEngineFactoryBean.setResourceLoaderPath("templates");
		VelocityEngine velocityEngine = velocityEngineFactoryBean.createVelocityEngine();*/
		
		
		VelocityEngine velocityEngine = (VelocityEngine) MailUtil.EmailEngine().get("velocityEngine");
		JsonObject smtpService = (JsonObject) MailUtil.EmailEngine().get("smtpService");
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			@Override
			public void prepare(MimeMessage mimeMessage) throws Exception {
			MimeMessageHelper message = new MimeMessageHelper(mimeMessage,true, "utf-8");
			    message.setSubject("接口调度异常通知");
				message.setTo(user.getEmailAddress());
				message.setFrom(GsonUtil.getString(smtpService, "emailAddress", "")); // could be parameterized...
				Map model = new HashMap();
				model.put("user", user);
				model.put("eps", eps);
				String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, 
						templateName+".vm", "utf-8", model);
				message.setText(text, true);
			}
		};
		JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl) MailUtil.EmailEngine().get("javaMailSenderImpl");
		javaMailSenderImpl.send(preparator);
	}
	
	
	public void sendMailBecauseClusterNodeRoot(User user,Collection<ClusterNode> clusterNodes,String templateName) throws IOException{
		
		/*JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl();
		
		JsonObject smtpService = paramSettingService.getAsJson(Keys.SMTP).getAsJsonObject();
		javaMailSenderImpl.setHost(GsonUtil.getString(smtpService, "smtpAddress", ""));
		javaMailSenderImpl.setPort(Integer.parseInt(GsonUtil.getString(smtpService, "port", "")));
		javaMailSenderImpl.setUsername(GsonUtil.getString(smtpService, "userCode", ""));
		javaMailSenderImpl.setPassword(GsonUtil.getString(smtpService, "password", ""));
		
		
		Properties javaMailProperties = new Properties();
		javaMailProperties.put(" mail.smtp.auth ", " true "); // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确
		javaMailProperties.put(" mail.smtp.timeout ", " 25000 ");
		javaMailSenderImpl.setJavaMailProperties(javaMailProperties);
		
		VelocityEngineFactoryBean velocityEngineFactoryBean = new VelocityEngineFactoryBean();
		velocityEngineFactoryBean.setResourceLoaderPath("templates");
		VelocityEngine velocityEngine = velocityEngineFactoryBean.createVelocityEngine();*/
		
		
		VelocityEngine velocityEngine = (VelocityEngine) MailUtil.EmailEngine().get("velocityEngine");
		JsonObject smtpService = (JsonObject) MailUtil.EmailEngine().get("smtpService");
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			@Override
			public void prepare(MimeMessage mimeMessage) throws Exception {
			MimeMessageHelper message = new MimeMessageHelper(mimeMessage,true, "utf-8");
			    message.setSubject("节点停止运行通知");
				message.setTo(user.getEmailAddress());
				message.setFrom(GsonUtil.getString(smtpService, "emailAddress", "")); // could be parameterized...
				Map model = new HashMap();
				model.put("user", user);
				model.put("clusterNodes", clusterNodes);
				String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, 
						templateName+".vm", "utf-8", model);
				message.setText(text, true);
			}
		};
		JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl) MailUtil.EmailEngine().get("javaMailSenderImpl");
		javaMailSenderImpl.send(preparator);
	}
	
	// 发送邮件方法
	public void CookSendEmail(Map model, String subject, String templateName) {
		VelocityEngine velocityEngine = (VelocityEngine) MailUtil.EmailEngine().get("velocityEngine");
		JsonObject smtpService = (JsonObject) MailUtil.EmailEngine().get("smtpService");
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			@Override
			public void prepare(MimeMessage mimeMessage) throws Exception {
				MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "utf-8");
				message.setSubject(subject);
				message.setTo((String) model.get("emailAddress"));
				message.setFrom(GsonUtil.getString(smtpService, "emailAddress", "")); // could
																						// be
																						// parameterized...
				String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateName + ".vm", "utf-8",
						model);
				message.setText(text, true);
			}
		};
		JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl) MailUtil.EmailEngine().get("javaMailSenderImpl");
		javaMailSenderImpl.send(preparator);
	}
	
	public void setMailMap(){
		
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		// 构建FROM和JOIN部分
		Root<InterfaceExceptionNotify> rootInterfaceExceptionNotify = cq.from(InterfaceExceptionNotify.class);
		// 构建WHERE部分
		List<Predicate> predicatesList = new ArrayList<>();
		cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
		// 构建GROUP BY部分
		cq.groupBy(rootInterfaceExceptionNotify.get("fieldName"),rootInterfaceExceptionNotify.get("fieldSystemName"),
				rootInterfaceExceptionNotify.get("interfaceName"),rootInterfaceExceptionNotify.get("sendToUsers"));
		
		cq.orderBy(cb.desc(rootInterfaceExceptionNotify.get("runBeginTime")));
		// 构建SELECT部分
		cq.multiselect(rootInterfaceExceptionNotify.get("sendToUsers").alias("sendToUsers"), rootInterfaceExceptionNotify.get("fieldName").alias("fieldName"),
				rootInterfaceExceptionNotify.get("fieldSystemName").alias("fieldSystemName"), rootInterfaceExceptionNotify.get("interfaceName").alias("interfaceName"),
				cb.count(rootInterfaceExceptionNotify.get("interfaceName")).alias("errorCount"));
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		// 执行查询
		List<Tuple> queryResult = q.getResultList();
		map.clear();
		for (Tuple tuple : queryResult) {
			String sendToUsers = tuple.get("sendToUsers",String.class);
			String fieldName = tuple.get("fieldName", String.class);
			String fieldSystemName = tuple.get("fieldSystemName", String.class);
			String interfaceName = tuple.get("interfaceName",String.class);
			Long errorCount = tuple.get("errorCount", Long.class);
			
			String users[] = StringUtils.split(sendToUsers, ";");
			for(int i=0;i<users.length;i++){
				User user = userRepository.findByUserCode(users[i]);
				map.putIfAbsent(user, new MultiKeyMap<>());
				MultiKeyMap<String, Long> map3 = map.get(user);
				
				if(map3.isEmpty()){
					map3.put(fieldName, fieldSystemName, interfaceName, errorCount);
				}else{
					if(map3.containsKey(fieldName, fieldSystemName, interfaceName)){
						Long errorCountTemp = map3.get(fieldName, fieldSystemName, interfaceName) + errorCount;
						map3.put(fieldName, fieldSystemName, interfaceName, errorCountTemp);
					}else{
						map3.put(fieldName, fieldSystemName, interfaceName, errorCount);
					}
				}
			}
		}
	}
	
	private String getExceptionTimeSlot(){
		String dateStr = "";
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		// 构建FROM和JOIN部分
		Root<InterfaceExceptionNotify> rootInterfaceExceptionNotify = cq.from(InterfaceExceptionNotify.class);
		// 构建WHERE部分
		List<Predicate> predicatesList = new ArrayList<>();
		cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
		// 构建GROUP BY部分
		/*cq.groupBy(rootInterfaceExceptionNotify.get("interfaceName"));
		
		cq.orderBy(cb.desc(rootInterfaceExceptionNotify.get("runBeginTime")));*/
		// 构建SELECT部分
		cq.multiselect(cb.min(rootInterfaceExceptionNotify.get("runBeginTime")).alias("minRunBeginTime"),
				cb.max(rootInterfaceExceptionNotify.get("runBeginTime")).alias("maxRunBeginTime"));
		
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		// 执行查询
		List<Tuple> queryResult = q.getResultList();
		for (Tuple tuple : queryResult) {
			String minRunBeginTime = tuple.get("minRunBeginTime",String.class);
			String maxRunBeginTime = tuple.get("maxRunBeginTime", String.class);
			dateStr = String.format("%s - %s", minRunBeginTime, maxRunBeginTime);
		}
		return dateStr;
	}
	
	
}
